/**
 *                            License
 * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS  
 * CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). 
 * THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.  
 * ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR  
 * COPYRIGHT LAW IS PROHIBITED.
 * 
 * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND  
 * AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE  
 * MAY BE CONSIDERED TO BE A CONTRACT,
 * THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED 
 * HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
 * 
 */
package lineage.database.tables;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Map;

import lineage.database.L1AbstractDatabase;
import lineage.model.instance.L1PcInstance;
import lineage.util.PerformanceTimer;
import lineage.util.Util;
import lineage.util.collections.Maps;

/**
 * 角色资料表.
 * 
 * @version 2014年3月19日下午10:01:17
 * @author jrwz
 */
public final class CharactersTable extends L1AbstractDatabase {
    private final Map<String, L1PcInstance> list = Maps.newHashMap();

    /**
     * 静态初始化器，由JVM来保证线程安全.
     */
    private static class Holder {
        static CharactersTable instance = new CharactersTable();
    }

    /**
     * 取得该类的实例.
     */
    public static CharactersTable getInstance() {
        return Holder.instance;
    }

    private CharactersTable() {
        batch("SELECT * FROM characters");
    }

    @Override
    protected void fillTable(final ResultSet rs) throws SQLException {
        final PerformanceTimer timer = new PerformanceTimer();
        final StringBuilder sb = new StringBuilder();
        sb.append("加载数据库：角色资料");

        while (rs.next()) {
            final L1PcInstance pc = new L1PcInstance();
            pc.setId(rs.getInt("objid"));
            pc.setAccountName(rs.getString("account_name"));
            pc.setName(rs.getString("name"));
            pc.setAccessLevel(rs.getInt("access_level"));
            pc.setLevel(rs.getInt("level"));
            pc.setExp(rs.getLong("exp"));
            pc.setHp(rs.getInt("hp"));
            pc.setMaxHP(rs.getInt("max_hp"));
            pc.setMp(rs.getInt("mp"));
            pc.setMaxMP(rs.getInt("max_mp"));
            pc.setAc(rs.getInt("ac"));
            pc.setStr(rs.getInt("str"));
            pc.setCon(rs.getInt("con"));
            pc.setDex(rs.getInt("dex"));
            pc.setWis(rs.getInt("wis"));
            pc.setInt(rs.getInt("intel"));
            pc.setCha(rs.getInt("cha"));
            pc.setSex(rs.getInt("sex"));
            pc.setClassId(rs.getInt("class_id"));
            pc.setType(rs.getInt("type"));
            pc.setSpareType(rs.getInt("spare_type"));
            pc.setHeading(rs.getInt("heading"));
            pc.setTempHeading(pc.getHeading());
            pc.setX(rs.getInt("loc_x"));
            pc.setY(rs.getInt("loc_y"));
            pc.setTempX(pc.getX());
            pc.setTempY(pc.getY());
            pc.setMapId(rs.getInt("map_id"));
            pc.setFood(rs.getInt("food"));
            pc.setLawful(rs.getInt("lawful"));
            pc.setTitle(rs.getString("title"));
            pc.setClanId(rs.getInt("clan_id"));
            pc.setClanName(rs.getString("clan_name"));
            pc.setClanRank(rs.getInt("clan_rank"));
            pc.setCreateTime(rs.getTimestamp("create_time"));
            pc.setDeleteTime(rs.getTimestamp("delete_time"));
            pc.setOriginalStr(rs.getInt("original_str"));
            pc.setOriginalCon(rs.getInt("original_con"));
            pc.setOriginalDex(rs.getInt("original_dex"));
            pc.setOriginalWis(rs.getInt("original_wis"));
            pc.setOriginalInt(rs.getInt("original_int"));
            pc.setOriginalCha(rs.getInt("original_cha"));

            put(pc); // 加入集合列表内
        }

        sb.append("(");
        sb.append(list.size());
        sb.append(")\t耗时 ");
        sb.append(timer.elapsedTimeMillis());
        sb.append(" 毫秒");
        Util.message(Util.SYSTEM_MESSAGE, sb.toString());
    }

    /**
     * 增加新角色(数据库+缓存内).
     * 
     * @param pc
     *            - 要增加的角色
     * @return 如果增加成功则返回true
     */
    public boolean addCharacters(final L1PcInstance pc) {
        boolean flag = false;
        StringBuilder sb = new StringBuilder();
        sb.append("INSERT INTO characters SET objid='");
        sb.append(pc.getId());
        sb.append("', account_name='");
        sb.append(pc.getAccountName());
        sb.append("', name='");
        sb.append(pc.getName());
        sb.append("', access_level='");
        sb.append(pc.getAccessLevel());
        sb.append("', level='");
        sb.append(pc.getLevel());
        sb.append("', exp='");
        sb.append(pc.getExp());
        sb.append("', hp='");
        sb.append(pc.getHp());
        sb.append("', max_hp='");
        sb.append(pc.getMaxHP());
        sb.append("', mp='");
        sb.append(pc.getMp());
        sb.append("', max_mp='");
        sb.append(pc.getMaxMP());
        sb.append("', ac='");
        sb.append(pc.getAc());
        sb.append("', str='");
        sb.append(pc.getStr());
        sb.append("', con='");
        sb.append(pc.getCon());
        sb.append("', dex='");
        sb.append(pc.getDex());
        sb.append("', wis='");
        sb.append(pc.getWis());
        sb.append("', intel='");
        sb.append(pc.getInt());
        sb.append("', cha='");
        sb.append(pc.getCha());
        sb.append("', sex='");
        sb.append(pc.getSex());
        sb.append("', class_id='");
        sb.append(pc.getClassId());
        sb.append("', type='");
        sb.append(pc.getType());
        sb.append("', spare_type='");
        sb.append(pc.getSpareType());
        sb.append("', heading='");
        sb.append(pc.getHeading());
        sb.append("', loc_x='");
        sb.append(pc.getX());
        sb.append("', loc_y='");
        sb.append(pc.getY());
        sb.append("', map_id='");
        sb.append(pc.getMapId());
        sb.append("', food='");
        sb.append(pc.getFood());
        sb.append("', lawful='");
        sb.append(pc.getLawful());
        sb.append("', title='");
        sb.append(pc.getTitle());
        sb.append("', clan_id='");
        sb.append(pc.getClanId());
        sb.append("', clan_name='");
        sb.append(pc.getClanName());
        sb.append("', clan_rank='");
        sb.append(pc.getClanRank());
        sb.append("', create_time='");
        sb.append(pc.getCreateTime());
        sb.append("', delete_time='");
        sb.append(pc.getDeleteTime());
        sb.append("', original_str='");
        sb.append(pc.getOriginalStr());
        sb.append("', original_con='");
        sb.append(pc.getOriginalCon());
        sb.append("', original_dex='");
        sb.append(pc.getOriginalDex());
        sb.append("', original_wis='");
        sb.append(pc.getOriginalWis());
        sb.append("', original_int='");
        sb.append(pc.getOriginalInt());
        sb.append("', original_cha='");
        sb.append(pc.getOriginalCha());
        sb.append("'");

        final boolean isAdd = updateResult(sb.toString()); // 存入数据库内
        if (isAdd) {
            put(pc); // 加入集合列表内

            sb = new StringBuilder();
            sb.append("帐号(");
            sb.append(pc.getAccountName());
            sb.append(")创建新角色：\t名称");
            sb.append("(");
            sb.append(pc.getName());
            sb.append(")\t职业(");
            final String[] type = new String[] { "王", "骑", "妖", "法", "黑", "龙", "幻" };
            sb.append(type[pc.getType()]);
            sb.append(")");
            Util.message(Util.SYSTEM_MESSAGE, sb.toString());
            flag = true;
        }
        return flag;
    }

    /**
     * 将角色的资料储存进数据库.
     * 
     * @param pc
     *            - 要储存的角色
     * @return 如果储存成功则返回true
     */
    public boolean storeCharacter(final L1PcInstance pc) {
        boolean flag = false;
        final StringBuilder sb = new StringBuilder();
        sb.append("UPDATE characters SET account_name='");
        sb.append(pc.getAccountName());
        sb.append("', name='");
        sb.append(pc.getName());
        sb.append("', access_level='");
        sb.append(pc.getAccessLevel());
        sb.append("', level='");
        sb.append(pc.getLevel());
        sb.append("', exp='");
        sb.append(pc.getExp());
        sb.append("', hp='");
        sb.append(pc.getHp());
        sb.append("', max_hp='");
        sb.append(pc.getMaxHP());
        sb.append("', mp='");
        sb.append(pc.getMp());
        sb.append("', max_mp='");
        sb.append(pc.getMaxMP());
        sb.append("', ac='");
        sb.append(pc.getAc());
        sb.append("', str='");
        sb.append(pc.getStr());
        sb.append("', con='");
        sb.append(pc.getCon());
        sb.append("', dex='");
        sb.append(pc.getDex());
        sb.append("', wis='");
        sb.append(pc.getWis());
        sb.append("', intel='");
        sb.append(pc.getInt());
        sb.append("', cha='");
        sb.append(pc.getCha());
        sb.append("', sex='");
        sb.append(pc.getSex());
        sb.append("', class_id='");
        sb.append(pc.getClassId());
        sb.append("', type='");
        sb.append(pc.getType());
        sb.append("', heading='");
        sb.append(pc.getHeading());
        sb.append("', loc_x='");
        sb.append(pc.getX());
        sb.append("', loc_y='");
        sb.append(pc.getY());
        sb.append("', map_id='");
        sb.append(pc.getMapId());
        sb.append("', food='");
        sb.append(pc.getFood());
        sb.append("', lawful='");
        sb.append(pc.getLawful());
        sb.append("', title='");
        sb.append(pc.getTitle());
        sb.append("', clan_id='");
        sb.append(pc.getClanId());
        sb.append("', clan_name='");
        sb.append(pc.getClanName());
        sb.append("', clan_rank='");
        sb.append(pc.getClanRank());
        sb.append("', delete_time='");
        sb.append(pc.getDeleteTime());
        sb.append("' WHERE objid='");
        sb.append(pc.getId());
        sb.append("'");

        final boolean isSave = updateResult(sb.toString());
        if (isSave) {
            put(pc); // 加入集合列表内
            flag = true;
        }
        return flag;
    }

    /**
     * 删除角色(数据库+缓存内).
     * 
     * @param pc
     *            - 要删除的角色
     * @return 如果删除成功则返回true
     */
    public boolean delCharacters(final L1PcInstance pc) {
        boolean flag = false;
        StringBuilder sb = new StringBuilder();
        sb.append("DELETE FROM characters WHERE objid='");
        sb.append(pc.getId());
        sb.append("'");

        final boolean isDel = updateResult(sb.toString());
        if (isDel) {
            remove(pc); // 从缓存中删除该角色

            sb = new StringBuilder();
            sb.append("删除角色：");
            sb.append("(");
            sb.append(pc.getName());
            sb.append(")");
            Util.message(Util.SYSTEM_MESSAGE, sb.toString());
            flag = true;
        }
        return flag;
    }

    /**
     * 更新角色删除时间 - 从当前时间算起7天之后(数据库内).
     * 
     * @param pc
     *            - 要更新的角色
     * @return 如果成功更改则返回true
     */
    public boolean updateDelTime(final L1PcInstance pc) {
        boolean flag = false;
        long nowTime = System.currentTimeMillis() / 1000;
        long deleteTime = (nowTime + 604800) * 1000; // 7天之后
        final StringBuilder sb = new StringBuilder();
        sb.append("UPDATE characters SET delete_time='");
        sb.append(new Timestamp(deleteTime));
        sb.append("' WHERE objid='");
        sb.append(pc.getId());
        sb.append("'");

        boolean isUp = updateResult(sb.toString());
        if (isUp) {
            pc.setDeleteTime(new Timestamp(deleteTime));
            put(pc); // 修改集合列表的相应内容
            flag = true;
        }
        return flag;
    }

    /**
     * 将新元素加入集合列表.
     * 
     * @param pc
     *            - L1PcInstance对象
     */
    public void put(final L1PcInstance pc) {
        list.put(String.valueOf(pc.getName()), pc);
    }

    /**
     * 检查是否已经有此角色名称.
     * 
     * @param name
     *            - 要检查的名称
     * @return 有则返回true
     */
    public boolean isName(final String name) {
        if (list.containsKey(name)) {
            return true;
        }
        return false;
    }

    /**
     * 根据角色名取得L1PcInstance对象.
     * 
     * @param name
     *            - 角色名
     * @return L1PcInstance对象(如果找不到则返回null)
     */
    public L1PcInstance getPc(final String name) {
        L1PcInstance pc = null;
        if (list.containsKey(name)) {
            pc = list.get(name);
        }
        return pc;
    }

    /**
     * 取得缓存列表.
     * 
     * @return 列表中的所有元素
     */
    public Map<String, L1PcInstance> get() {
        return list;
    }

    /**
     * 取得缓存列表.
     * 
     * @return 列表中的所有元素
     */
    public Collection<L1PcInstance> getList() {
        return list.values();
    }

    /**
     * 根据角色名从缓存列表中删除指定角色.
     * 
     * @param name
     *            - 要删除角色的名称
     */
    public void remove(final String name) {
        if (list.containsKey(name)) {
            list.remove(name);
        }
    }

    /**
     * 从缓存列表中删除指定角色.
     * 
     * @param pc
     *            - 要删除的角色
     */
    public void remove(final L1PcInstance pc) {
        final String name = pc.getName();
        if (list.containsKey(name)) {
            list.remove(name);
        }
    }
}
